package com.example.musicplayer.gobang;

import java.util.HashMap;

public class AI_1 {
    private final int SIZE;
    //record score of each location
    private final int[][] mScore;
    private final Gobang mGobang;

    public AI_1(Gobang gobang) {
        mGobang = gobang;
        SIZE = gobang.getChessBoardSize();
        mScore = new int[SIZE][SIZE];
    }

    public Location nextLocation() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                mScore[i][j] = 0;
            }
        }
        calculateScore();
        int maxScore = 0;
        int x = 0;
        int y = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (mScore[i][j] > maxScore) {
                    maxScore = mScore[i][j];
                    x = i;
                    y = j;
                }
            }
        }
        return new Location(x, y);
    }

    //calculate each score in empty location
    private void calculateScore() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (mGobang.getChess(i, j) == Gobang.EMPTY) {
                    mScore[i][j] = scoreH(i, j) + scoreV(i, j) + scoreFS(i, j) + scoreBS(i, j);
                }
            }
        }
    }

    //score in horizontal
    private int scoreH(int x, int y) {
        String code = "1";
        int score = 0;
        //this side to left
        for (int k = 1; ; k++) {
            if (y - k >= 0) {
                if (mGobang.getChess(x, y - k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x, y - k) == mGobang.getRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //this side to right
        for (int k = 1; ; k++) {
            if (y + k < SIZE) {
                if (mGobang.getChess(x, y + k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x, y + k) == mGobang.getRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        Integer value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        //other side to left
        code = "1";
        for (int k = 1; ; k++) {
            if (y - k >= 0) {
                if (mGobang.getChess(x, y - k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x, y - k) == mGobang.getOppositeRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //other side to right
        for (int k = 1; ; k++) {
            if (y + k < SIZE) {
                if (mGobang.getChess(x, y + k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x, y + k) == mGobang.getOppositeRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        return score;
    }

    //score in vertical
    private int scoreV(int x, int y) {
        String code = "1";
        int score = 0;
        //this side up
        for (int k = 1; ; k++) {
            if (x - k >= 0) {
                if (mGobang.getChess(x - k, y) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y) == mGobang.getRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //this side down
        for (int k = 1; ; k++) {
            if (x + k < SIZE) {
                if (mGobang.getChess(x + k, y) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y) == mGobang.getRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        Integer value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        //other side up
        code = "1";
        for (int k = 1; ; k++) {
            if (x - k >= 0) {
                if (mGobang.getChess(x - k, y) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y) == mGobang.getOppositeRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //other side to right
        for (int k = 1; ; k++) {
            if (x + k < SIZE) {
                if (mGobang.getChess(x + k, y) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y) == mGobang.getOppositeRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        return score;
    }

    //score in forward slash
    private int scoreFS(int x, int y) {
        String code = "1";
        int score = 0;
        //this side to right-up
        for (int k = 1; ; k++) {
            if (x - k >= 0 && y + k < SIZE) {
                if (mGobang.getChess(x - k, y + k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y + k) == mGobang.getRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //this side to left-down
        for (int k = 1; ; k++) {
            if (x + k < SIZE && y - k >= 0) {
                if (mGobang.getChess(x + k, y - k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y - k) == mGobang.getRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        Integer value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        //other side to right-up
        code = "1";
        for (int k = 1; ; k++) {
            if (x - k >= 0 && y + k < SIZE) {
                if (mGobang.getChess(x - k, y + k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y + k) == mGobang.getOppositeRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //other side to right
        for (int k = 1; ; k++) {
            if (x + k < SIZE && y - k >= 0) {
                if (mGobang.getChess(x + k, y - k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y - k) == mGobang.getOppositeRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        return score;
    }

    //score in back slash
    private int scoreBS(int x, int y) {
        String code = "1";
        int score = 0;
        //this side to left-up
        for (int k = 1; ; k++) {
            if (x - k >= 0 && y - k >= 0) {
                if (mGobang.getChess(x - k, y - k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y - k) == mGobang.getRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //this side to right-down
        for (int k = 1; ; k++) {
            if (x + k < SIZE && y + k < SIZE) {
                if (mGobang.getChess(x + k, y + k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y + k) == mGobang.getRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        Integer value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        //other side to left-up
        code = "1";
        for (int k = 1; ; k++) {
            if (x - k >= 0 && y - k >= 0) {
                if (mGobang.getChess(x - k, y - k) == Gobang.EMPTY) {
                    code = "0" + code;
                    break;
                } else if (mGobang.getChess(x - k, y - k) == mGobang.getOppositeRound()) {
                    code = "1" + code;
                } else {
                    code = "2" + code;
                    break;
                }
            } else {
                code = "0" + code;
                break;
            }
        }
        //other side to right-down
        for (int k = 1; ; k++) {
            if (x + k < SIZE && y + k < SIZE) {
                if (mGobang.getChess(x + k, y + k) == Gobang.EMPTY) {
                    code = code + "0";
                    break;
                } else if (mGobang.getChess(x + k, y + k) == mGobang.getOppositeRound()) {
                    code = code + "1";
                } else {
                    code = code + "2";
                    break;
                }
            } else {
                code = code + "0";
                break;
            }
        }
        value = ScoreTable.TABLE.get(code);
        if (value == null) {
            score += ScoreTable.MAX_SCORE;
        } else {
            score += value;
        }
        return score;
    }

    //0 means empty or edge, 1 means 己方棋子, 2 means 对方棋子
    private static class ScoreTable {
        public static final HashMap<String, Integer> TABLE = new HashMap<String, Integer>();
        public static final int MAX_SCORE = 200000;

        static {
            //five in a row
            TABLE.put("0111110", 200000);
            TABLE.put("0111112", 200000);
            TABLE.put("2111110", 200000);
            TABLE.put("2111112", 200000);
            //four in a row
            TABLE.put("011110", 50000);
            TABLE.put("011112", 3000);
            TABLE.put("211110", 3000);
            TABLE.put("211112", 1000);
            //three in a row
            TABLE.put("01110", 3000);
            TABLE.put("01112", 1000);
            TABLE.put("21110", 1000);
            TABLE.put("21112", 500);
            //two in a row
            TABLE.put("0110", 500);
            TABLE.put("0112", 200);
            TABLE.put("2110", 200);
            TABLE.put("2112", 100);
            //only one
            TABLE.put("010", 100);
            TABLE.put("012", 50);
            TABLE.put("210", 50);
            TABLE.put("212", 30);
        }
    }
}